package fab.swfparser
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	
	public class SWFParser extends Sprite 
	{
		private var parseLog:String;

		// handlers for SWF tags
		// for example: 
		// handlers[6] = parseJPEG; 
		// to set your handler for DefineBitsJPEG tag.
		// you can find SWF file specifications in Google.
		private var handlers:Array = [];
		public var symbols:Array = [];
		public var symbolsNames:Array = [];

		public function SWFParser(swfBytes:ByteArray = null) {
			
			handlers[76] = parseSymbolClass; 
			parseSWF(swfBytes);
		}
		override public function toString():String {
			return parseLog;
		}
		
		
		static public function parseBytes(swfBytes:ByteArray = null):SWFParser {
			
			var parser:SWFParser = new SWFParser( swfBytes );
			return parser;
		}
		public function getSymbolsNames():Array
		{
			return symbolsNames;
		}
		
		

		private function parseSymbolClass(tag:uint, id:int, size:int, dump:ByteArray):void
		{
			dump.endian = Endian.LITTLE_ENDIAN;
			var NumSymbols:uint = dump.readUnsignedShort();
			for (var i:int = 0; i < NumSymbols; i++ )
			{
				var symbolObject:Object = { tag:dump.readUnsignedShort(), name:readString( dump ) };
				symbols.push( symbolObject );
				symbolsNames.push( symbolObject.name );				
			}
			parseLog += "\n";
			parseLog += "parseSymbolClass : " + NumSymbols + " symbols :\n" + symbolsNames.join( "\n" ) + "\n";
		}
		
		
		private function readString(bytes:ByteArray):String
		{
			// find ending null character that
			// terminates the string
			var i:uint = bytes.position;
			try {
				while(bytes[i] != 0) i++;
			}catch (error:Error) {
				return "";
			}
			var string:String = bytes.readUTFBytes(i - bytes.position);
			bytes.readByte();
			// null byte should have been found
			// return the read string
			return string;
		}
		
		
		//http://flashpanoramas.com/blog/2007/07/02/swf-parser-air-application/
		private function parseSWF(data:ByteArray):void {

			parseLog = "";
			data.endian = Endian.LITTLE_ENDIAN;
			var format:String = data.readUTFBytes(3);
			var compressed:Boolean = format=="CWS";
			if (format=="FWS" || format=="CWS") {
				parseLog += "SWF version "+data.readByte();
				parseLog += ", size: "+data.readUnsignedInt();
			} else {
				parseLog += "Not a Flash file.";
				return;
			}
			data.readBytes(data);
			data.length -= 8;
			if (compressed) {
				data.uncompress();
			}
			data.position = 0;
			var frame:Array = readBox(data);
			parseLog += "\n";
			parseLog += "Width: "+Math.round((frame[1]-frame[0])/20);// in swf, length are in twips : 1/20 of a pixel
			parseLog += ", height: "+Math.round((frame[3]-frame[2])/20);
			var fps_f:uint = data.readUnsignedByte();
			var fps_i:uint = data.readUnsignedByte();
			parseLog += "\n";
			parseLog += "FPS: "+(fps_i+fps_f/256);
			var count:uint = data.readUnsignedShort();
			parseLog += "\n";
			parseLog += "Total frames: "+count;
			parseLog += "\n";
			while (data.bytesAvailable) {
				readSWFTag(data);
			}
			//trace(parseLog);
		}

		// read SWF tag and call handler if present
		private function readSWFTag(data:ByteArray):void {
			var tag:uint = data.readUnsignedShort();// 16 bits
			var id:int = tag>>6;// les 10 premiers => tag type
			var size:int = tag & 0x3F;
			if (size == 0x3F) {
				size = data.readUnsignedInt();// 2 types de Tag : the short and long tag header
			}
			parseLog += "\n";
			parseLog += "Tag "+id;
			if (handlers[id]!=null) {
				var dump:ByteArray = new ByteArray();
				if (size!=0) {
					data.readBytes(dump,0,size);
				}
				handlers[id](tag, id, size, dump);
			} else {
				data.position += size;
			}
			parseLog += "\tsize: "+size;
		}

		// read compressed box format
		private function readBox(data:ByteArray):Array {
			var c:Array = [];
			var current:uint = data.readUnsignedByte();
			var size:uint = current>>3;
			var off:int = 3;
			for (var i:int=0; i<4; i+=1) {
				c[i] = current<<(32-off)>>(32-size);
				off -= size;
				while (off<0) {
					current = data.readUnsignedByte();
					c[i] |= off<-8?current<<(-off-8):current>>(-off-8);
					off += 8;
				}
			}
			return c;
		}

		
		//http://www.slideshare.net/sawrub/hacking-swf
/*
0 End
1 ShowFrame
2 DefineShape
4 PlaceObject
5 RemoveObject
6 DefineBits
7 DefineButton
8 JPEGTables
9 SetBackgroundColor
10 DefineFont
11 DefineText
12 DoAction
13 DefineFontInfo
14 DefineSound
15 StartSound
17 DefineButtonSound
18 SoundStreamHead
19 SoundStreamBlock
20 DefineBitsLossless
21 DefineBitsJPEG2
22 DefineShape2
23 DefineButtonCxform
24 Protect
26 PlaceObject2
28 RemoveObject2
32 DefineShape3
33 DefineText2
34 DefineButton2
35 DefineBitsJPEG3
36 DefineBitsLossless2
37 DefineEditText
39 DefineSprite
43 FrameLabel
45 SoundStreamHead2
46 DefineMorphShape
48 DefineFont2
56 ExportAssets
57 ImportAssets
58 EnableDebugger
59 DoInitAction
60 DefineVideoStream
61 VideoFrame
62 DefineFontInfo2
64 EnableDebugger2
65 ScriptLimits
66 SetTabIndex
69 FileAttributes
70 PlaceObject3
71 ImportAssets2
73 DefineFontAlignZones
74 CSMTextSettings
75 DefineFont3
76 SymbolClass
77 Metadata
78 DefineScalingGrid
82 DoABC
83 DefineShape4
84 DefineMorphShape2
86 DefineSceneAndFrameLabelData
87 DefineBinaryData
88 DefineFontName
89 StartSound2
90 DefineBitsJPEG4
91 DefineFont4
*/

	}
	
}